/*
 * @Author: wuqingchun
 * @Date: 2024-03-20 21:02:15
 * @Description: 
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-04-01 19:39:53
 */
#include <arpa/inet.h>

#include "utcp_socket.h"
#include "utcp_util.h"
#include "utcp_timer.h"


int32_t client(const char* pcSvrHostname, uint16_t usPort)
{
    CUTCPSocket objSocket;

    int32_t iErr = objSocket.Open();
    if (iErr != UTCP_SUCCESS)
    {
        return 0;
    }

    struct sockaddr_in stPeerAddr = {};
    stPeerAddr.sin_family = AF_INET;
    stPeerAddr.sin_addr.s_addr = inet_addr(pcSvrHostname);
    stPeerAddr.sin_port = htons(usPort);

    if (objSocket.Connect((sockaddr*)&stPeerAddr, sizeof(stPeerAddr)) != UTCP_SUCCESS)
    {
        return 0;
    }

    ssize_t lLen = objSocket.Send("Hello server", sizeof("Hello server"), 0);
    if (lLen <= 0)
    {
        printf("Send error\n");
        return 0;
    }

    char acBuf[1024];
    lLen = objSocket.Recv(acBuf, 1024, 0);
    if (lLen > 0)
    {
        printf("Recv: %s, %ld\n", acBuf, lLen);
    }
}

int32_t server()
{
    CUTCPSocket objSocket;

    int32_t iErr = objSocket.Open();
    if (iErr != UTCP_SUCCESS)
    {
        return 0;
    }

    struct sockaddr_in stLocalAddr = {};
    stLocalAddr.sin_family = AF_INET;
    stLocalAddr.sin_addr.s_addr = INADDR_ANY;
    stLocalAddr.sin_port = htons(8888);
    iErr = objSocket.Bind((const struct sockaddr*)&stLocalAddr, sizeof(stLocalAddr));
    if (iErr != UTCP_SUCCESS)
    {
        objSocket.Close();
        return 0;
    }

    iErr = objSocket.Listen(100);
    if (iErr != UTCP_SUCCESS)
    {
        objSocket.Close();
        return 0;
    }

    while (1)
    {
        sockaddr_in stPeerAddr = {};
        socklen_t uiAddrLen = sizeof(stPeerAddr);
        CUTCPSocket* pobjSubSocket = objSocket.Accept((sockaddr*)&stPeerAddr, &uiAddrLen);
        if (pobjSubSocket == nullptr)
        {
            continue;
        }

        char szAddr[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &stPeerAddr.sin_addr.s_addr, szAddr, INET_ADDRSTRLEN);

        printf("Accept %s:%hu successfully.\n", szAddr, stPeerAddr.sin_port);
        char acBuf[1024];
        ssize_t lLen = pobjSubSocket->Recv(acBuf, 1024, 0);
        if (lLen > 0)
        {
            printf("Recv: %s, %ld\n", acBuf, lLen);

            lLen = pobjSubSocket->Send("Hello client", sizeof("Hello client"), 0);
            if (lLen > 0)
            {
                printf("Send successfully, %ld\n", lLen);
            }
        }
    }

    return 0;
}

void timer_test()
{
    UTCPTimer objTimer;

    objTimer.AddTask(1000000000, 0, [](void* arg){ std::cout << "Timeout 2s " << std::endl;});
    objTimer.AddTask(1000000000, 0, [](void* arg){ std::cout << "Timeout 3s " << std::endl;});

    objTimer.Start();

    std::this_thread::sleep_for(std::chrono::seconds(2));
    objTimer.AddTask(0, 1000000000, [](void* arg){ std::cout << "Timeout 1s " << std::endl;});

    pause();
}

int main(int argc, char** argv)
{
    int32_t iMode = 0;

    timer_test();

    if (argc > 1)
    {
        iMode = atoi(argv[1]);
    }

    if (iMode == 0)
    {
        server();
    }
    else
    {
        if (argc < 4)
        {
            return 0;
        }

        client(argv[2], atoi(argv[3]));
    }
    
    return 0;
}